package main

import (
	"database/sql"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// realmFlags 服务器标志
type realmFlags byte

const (
	realmFlagOffline      realmFlags = 0x02 // 离线
	realmFlagSpecifyBuild realmFlags = 0x04 // 特殊构建版本
	realmFlagNewPlayers   realmFlags = 0x20 // 新玩家
	realmFlagRecommended  realmFlags = 0x40 // 建议
)

// realm 服务器信息
type realm struct {
	id           uint32     // 服务器编号
	name         string     // 服务器名字
	address      string     // 服务器地址
	icon         byte       // 服务器图标
	realmFlags   realmFlags // 服务器标志
	timeZone     byte       // 时区
	populationLv float32    // 热度
	builds       []uint32   // 支持的构建版本
}

// realmList 服务器列表
type realmList struct {
	realms         map[string]realm // 服务器列表
	lastUpdateTime int64            // 上次更新时间
}

// init 初始化
func (rl *realmList) init() {
	rl.realms = make(map[string]realm)
}

// update 更新服务器列表
func (rl *realmList) update(init bool) {
	rl.lastUpdateTime = time.Now().Unix()
	rl.updateRealms(init)
}

// updateIfNeed 如果需要更新则更新
func (rl *realmList) updateIfNeed() {
	now := time.Now().Unix()
	if (now - rl.lastUpdateTime) > 60 {
		rl.update(false)
	}
}

// getRealms 获取服务器列表
func (rl *realmList) getRealms() []realm {
	var realms []realm
	for _, rm := range rl.realms {
		realms = append(realms, rm)
	}
	return realms
}

// updateRealms 更新服务器列表
func (rl *realmList) updateRealms(init bool) {
	log("更新服务器列表")

	// 查询数据
	rows, err := rDB.Query("SELECT id, name, address, port, icon, realmflags, timezone, allowedSecurityLevel, population, realmbuilds FROM realmlist WHERE (realmflags & 1) = 0 ORDER BY name")
	if err != nil {
		if !errors.Is(err, sql.ErrNoRows) {
			logDBError("%v", err)
		}
		return
	}
	// 关闭数据
	defer func(rows *sql.Rows) {
		err := rows.Close()
		if err != nil {
			logDBError("%v", err)
		}
	}(rows)
	// 遍历数据
	for rows.Next() {
		var (
			id         uint32
			name       string
			address    string
			port       uint32
			icon       uint8
			rFlags     uint8
			timezone   uint8
			secLv      uint8
			population float32
			rBuilds    string
		)

		if err = rows.Scan(&id, &name, &address, &port, &icon,
			&rFlags, &timezone, &secLv, &population, &rBuilds); err != nil {
			logDBError("%v", err)
			break
		}
		if (rFlags & ^uint8(realmFlagOffline|realmFlagNewPlayers|realmFlagRecommended|realmFlagSpecifyBuild)) != 0 {
			logDBError("服务器 (编号 %d, 名字 '%s') 只能在数据库中被标记为离线 (标志 0x02), "+
				"新玩家 (标志 0x20), 建议 (标志 0x40), 或者 特殊构建 (标志 0x04)",
				id, name)
			rFlags &= uint8(realmFlagOffline | realmFlagNewPlayers | realmFlagRecommended | realmFlagSpecifyBuild)
		}

		rl.updateRealm(id, name, address, port, icon, realmFlags(rFlags), timezone,
			population, rBuilds)

		if init {
			log("添加服务器：%d, %s", id, name)
		}
	}
}

// updateRealm 更新服务器
func (rl *realmList) updateRealm(id uint32, name string, address string,
	port uint32, icon uint8, flags realmFlags,
	timezone uint8, population float32,
	builds string) {
	rm, ok := rl.realms[name]
	if !ok {
		rm = realm{}
	}

	rm.id = id
	rm.name = name
	rm.icon = icon
	rm.realmFlags = flags
	rm.timeZone = timezone
	rm.populationLv = population
	rm.address = fmt.Sprintf("%s:%d", address, port)

	// 读取构建版本
	tokens := strings.Split(builds, " ")
	rm.builds = rm.builds[:0]
	for _, token := range tokens {
		build, err := strconv.Atoi(token)
		if err == nil {
			rm.builds = append(rm.builds, uint32(build))
		}
	}

	// 检查构建版本
	var firstBuild uint32 = 0
	if len(rm.builds) > 0 {
		firstBuild = rm.builds[0]
	}
	if firstBuild <= 0 {
		logError("这个服务器没有被允许的构建版本: %s", name)
	}

	// 加入服务器表
	rl.realms[name] = rm
}
